{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ef5572ea-29ca-4eb4-bf84-2b86ff489c88",
   "metadata": {},
   "outputs": [],
   "source": [
    "# imports\n",
    "\n",
    "import os\n",
    "import json\n",
    "from dotenv import load_dotenv\n",
    "from openai import OpenAI\n",
    "import subprocess\n",
    "import tempfile\n",
    "from IPython.display import Markdown, display, update_display"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "38ae1ba0-d4b3-41c5-aca1-759d1c597749",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Initialization\n",
    "\n",
    "load_dotenv()\n",
    "\n",
    "openai_api_key = os.getenv('OPENAI_API_KEY')\n",
    "if openai_api_key:\n",
    "    print(f\"OpenAI API Key exists and begins {openai_api_key[:8]}\")\n",
    "else:\n",
    "    print(\"OpenAI API Key not set\")\n",
    "    \n",
    "MODEL_NAME = \"gpt-4o\"\n",
    "openai = OpenAI()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a07e7793-b8f5-44f4-aded-5562f633271a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import sys\n",
    "import openai\n",
    "import subprocess\n",
    "import tempfile\n",
    "import base64\n",
    "import glob\n",
    "\n",
    "# Assurez-vous d'avoir défini openai.api_key = \"...\" et MODEL_NAME = \"...\".\n",
    "# Par exemple :\n",
    "# openai.api_key = \"sk-...\"\n",
    "# MODEL_NAME = \"gpt-4\"  # Ou \"gpt-3.5-turbo\", etc.\n",
    "\n",
    "def encode_image(image_path):\n",
    "    \"\"\"\n",
    "    Encode un fichier image en base64 (chaîne de caractères).\n",
    "    \"\"\"\n",
    "    with open(image_path, \"rb\") as f:\n",
    "        return base64.b64encode(f.read()).decode(\"utf-8\")\n",
    "\n",
    "# --------------------------------------------------------------------\n",
    "# 2) Fonctions pour générer le code à partir d'une preuve\n",
    "# --------------------------------------------------------------------\n",
    "def generate_test_code(proof_text):\n",
    "    \"\"\"\n",
    "    Envoie la preuve mathématique à l'API OpenAI\n",
    "    et récupère un code Python qui permet de tester ou de valider la preuve.\n",
    "    \"\"\"\n",
    "    system_msg = (\n",
    "        \"Tu es un assistant IA spécialisé en mathématiques et en programmation. \"\n",
    "        \"Tu vas recevoir une preuve mathématique, et tu dois générer du code Python \"\n",
    "        \"pour la tester ou la valider expérimentalement. \"\n",
    "        \"Le code doit inclure (au moins) la génération de données pertinentes, \"\n",
    "        \"la logique de test ou de simulation, puis l'affichage ou l'export des résultats (texte/graphique).\"\n",
    "        \"Inclus uniquement le code généré dans ta réponse, aucun commentaire en langage naturel. \"\n",
    "        \"Assure-toi d'enregistrer toute image générée dans un dossier 'generated_outputs' pour que nous puissions la retrouver.\"\n",
    "    )\n",
    "    \n",
    "    user_msg = (\n",
    "        f\"Voici la preuve mathématique proposée :\\n\\n{proof_text}\\n\\n\"\n",
    "        \"Génère du code Python pour tester la validité de cette preuve, \"\n",
    "        \"par simulation ou analyse. Le code doit produire un résumé \"\n",
    "        \"des résultats, et, si possible, un graphique (enregistré dans le dossier 'generated_outputs' \"\n",
    "        \"au format PNG).\"\n",
    "    )\n",
    "\n",
    "    response = openai.chat.completions.create(\n",
    "        model=MODEL_NAME,\n",
    "        messages=[\n",
    "            {\"role\": \"system\", \"content\": system_msg},\n",
    "            {\"role\": \"user\", \"content\": user_msg}\n",
    "        ],\n",
    "        temperature=0.2  # Limiter la créativité pour un code plus \"déterministe\"\n",
    "    )\n",
    "\n",
    "    generated_code = response.choices[0].message.content\n",
    "    return generated_code\n",
    "\n",
    "# --------------------------------------------------------------------\n",
    "# 3) Fonction pour exécuter le code généré\n",
    "# --------------------------------------------------------------------\n",
    "def run_generated_code(code):\n",
    "    \"\"\"\n",
    "    Écrit le code dans un fichier temporaire et l'exécute dans un dossier\n",
    "    où il pourra sauvegarder ses images. Capture stdout et stderr.\n",
    "    \"\"\"\n",
    "\n",
    "    # On crée un répertoire \"generated_outputs\" si non existant\n",
    "    output_dir = \"generated_outputs\"\n",
    "    if not os.path.exists(output_dir):\n",
    "        os.makedirs(output_dir)\n",
    "\n",
    "    # On insère un petit snippet pour forcer le code à utiliser ce dossier\n",
    "    # s'il fait un plt.savefig(...) par exemple. \n",
    "    # (Optionnel, si l'IA ne le fait pas déjà.)\n",
    "    # On pourrait injecter du code, mais ici on se contente\n",
    "    # de supposer que l'IA respectera le prompt.\n",
    "    \n",
    "    # Ecriture du code dans un fichier temporaire\n",
    "    with tempfile.NamedTemporaryFile(suffix=\".py\", delete=False, mode='w', encoding='utf-8') as tmp_file:\n",
    "        tmp_filename = tmp_file.name\n",
    "        tmp_file.write(code)\n",
    "    \n",
    "    try:\n",
    "        # Exécution du code dans le répertoire courant\n",
    "        result = subprocess.run(\n",
    "            [\"python\", tmp_filename],\n",
    "            capture_output=True,\n",
    "            text=True,\n",
    "            check=False  # On met check=False pour capturer l'erreur sans lever l'exception\n",
    "        )\n",
    "        stdout = result.stdout\n",
    "        stderr = result.stderr\n",
    "    finally:\n",
    "        os.remove(tmp_filename)\n",
    "    \n",
    "    return stdout, stderr\n",
    "\n",
    "# --------------------------------------------------------------------\n",
    "# 4) Fonction pour interpréter les résultats en streaming Markdown\n",
    "#    + Possibilité de joindre une image (ou plusieurs) depuis generated_outputs\n",
    "# --------------------------------------------------------------------\n",
    "def interpret_results_streaming(proof_text, generated_code, stdout, stderr):\n",
    "    \"\"\"\n",
    "    Envoie le code (generated_code) et les résultats de l'exécution (stdout, stderr) à l'API pour une interprétation textuelle\n",
    "    au regard de la preuve fournie, en mode streaming.\n",
    "\n",
    "    Cette fois, on va automatiquement scanner le dossier 'generated_outputs'\n",
    "    pour chercher tous les .png. On les insère un par un dans le message.\n",
    "    \"\"\"\n",
    "    system_msg = (\n",
    "        \"Tu es un assistant IA spécialisé en mathématiques et en interprétation de résultats de simulation. \"\n",
    "        \"On te fournit la preuve initiale et le code d'une simulation ainsi que ses retours (generated_code, stdout, stderr). \"\n",
    "        \"Donne une analyse de la cohérence entre la preuve, le code et les résultats, \"\n",
    "        \"et retourne ta réponse au format Markdown.\"\n",
    "    )\n",
    "\n",
    "    # On construit un 'content' qui est un tableau \n",
    "    # (selon l'exemple de code que vous avez fourni).\n",
    "    user_content = [\n",
    "        {\n",
    "            \"type\": \"text\",\n",
    "            \"text\": (\n",
    "                f\"Preuve initiale :\\n{proof_text}\\n\\n\"\n",
    "                f\"Code de la simulation :\\n{generated_code}\\n\\n\"\n",
    "                f\"Résultats (stdout) :\\n{stdout}\\n\\n\"\n",
    "                f\"Erreurs éventuelles (stderr) :\\n{stderr}\\n\\n\"\n",
    "                \"Merci d'interpréter ces résultats et de conclure sur la preuve. \"\n",
    "                \"Formule ta réponse de manière structurée en Markdown.\\n\"\n",
    "            )\n",
    "        }\n",
    "    ]\n",
    "\n",
    "    # On cherche toutes les images PNG qui auraient pu être générées \n",
    "    # dans le dossier \"generated_outputs\"\n",
    "    output_dir = \"generated_outputs\"\n",
    "    png_files = glob.glob(os.path.join(output_dir, \"*.png\"))\n",
    "\n",
    "    # Pour chacune, on l'encode en base64 et on l'ajoute\n",
    "    for png_path in png_files:\n",
    "        encoded_img = encode_image(png_path)\n",
    "        # On ajoute un bloc \"image_url\"\n",
    "        user_content.append({\n",
    "            \"type\": \"image_url\",\n",
    "            \"image_url\": {\"url\": f\"data:image/png;base64,{encoded_img}\"}\n",
    "        })\n",
    "\n",
    "    # Appel en mode streaming\n",
    "    response_stream = openai.chat.completions.create(\n",
    "        model=MODEL_NAME,\n",
    "        messages=[\n",
    "            {\"role\": \"system\", \"content\": system_msg},\n",
    "            {\"role\": \"user\", \"content\": user_content}\n",
    "        ],\n",
    "        temperature=0.2,\n",
    "        stream=True\n",
    "    )\n",
    "    \n",
    "    # On débute un bloc Markdown\n",
    "    response = \"\"\n",
    "    display_handle = display(Markdown(\"\"), display_id=True)\n",
    "    for chunk in response_stream:\n",
    "        response += chunk.choices[0].delta.content or ''\n",
    "        response = response.replace(\"```\",\"\").replace(\"markdown\", \"\")\n",
    "        update_display(Markdown(response), display_id=display_handle.display_id)\n",
    "\n",
    "# --------------------------------------------------------------------\n",
    "# 5) Fonction principale (à appeler directement dans le notebook)\n",
    "# --------------------------------------------------------------------\n",
    "def main(proof_text: str):\n",
    "    print(\"=== Génération du code Python pour tester la preuve... ===\")\n",
    "    test_code = generate_test_code(proof_text)\n",
    "\n",
    "    # --- Nettoyage des backticks Markdown ---\n",
    "    lines = test_code.splitlines()\n",
    "    cleaned_lines = []\n",
    "    for line in lines:\n",
    "        if line.strip().startswith(\"```\"):\n",
    "            continue\n",
    "        cleaned_lines.append(line)\n",
    "    test_code = \"\\n\".join(cleaned_lines).strip()\n",
    "    # ----------------------------------------\n",
    "\n",
    "    print(\"\\n=== Code généré (nettoyé) : ===\")\n",
    "    print(test_code)\n",
    "\n",
    "    print(\"\\n=== Exécution du code généré... ===\")\n",
    "    stdout, stderr = run_generated_code(test_code)\n",
    "\n",
    "    print(\"\\n=== Sortie standard (stdout) : ===\")\n",
    "    print(stdout)\n",
    "    if stderr.strip():\n",
    "        print(\"\\n=== Erreurs (stderr) : ===\")\n",
    "        print(stderr)\n",
    "\n",
    "    print(\"\\n=== Interprétation des résultats (streaming en Markdown) ===\")\n",
    "    interpret_results_streaming(proof_text, test_code, stdout, stderr)\n",
    "    \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1120131d-48f1-4fdc-8950-70312b8228df",
   "metadata": {},
   "outputs": [],
   "source": [
    "mon_texte_de_preuve = \"\"\"\n",
    "Ci-dessous, je propose une ébauche (relativement détaillée) d’une approche formelle pour construire un objet « cosmohedron-like » et démontrer (ou du moins argumenter rigoureusement) qu’il possède des propriétés fractales dans une limite bien définie. Attention : dans l’état actuel des recherches, la littérature ne fournit pas (à ma connaissance) de démonstration largement reconnue établissant qu’un « vrai » cosmohedron est strictement fractal. Ce que je vais donc présenter est un modèle mathématisé inspiré des idées de cosmohedra et de leur possible fractalité, en détaillant :\n",
    "La définition axiomatique (ou construction) d’une famille {Cn}n∈N\\{C_n\\}_{n \\in \\mathbb{N}}{Cn​}n∈N​ d’objets géométriques (polytopes) qui tendent vers une limite.\n",
    "Les propriétés de self-similarité ou d’auto-similarité approchée qui sont au cœur d’une structure fractale.\n",
    "Une preuve (ou un argument) de non-invariance d’échelle integer-valued (c’est-à-dire que la dimension n’est pas un entier fixe) en s’appuyant sur une analyse de la « taille » de l’objet à différentes échelles.\n",
    "Une conclusion sur la (quasi-)fractalité ou la fractalité effective de la limite de {Cn}\\{C_n\\}{Cn​}.\n",
    "\n",
    "1. Définition d’une famille de polytopes « cosmohedron-like »\n",
    "1.1. Construction combinatoire\n",
    "Les cosmohedra (au sens de la littérature actuelle) se définissent via des données combinatoires et cinématiques (angles, énergie, moment, variables conformes, etc.) associées à la fonction d’onde cosmologique. Pour formaliser, on peut s’inspirer d’une définition axiomatique :\n",
    "On part d’un polygone (ou polytope) de base Π0\\Pi_0Π0​ en dimension ddd (avec d≥2d \\ge 2d≥2, souvent la dimension 2 sert d’analogue).\n",
    "On définit une liste de coupes ou « partitions » (généralisant la notion de triangulation) qui correspond, dans le contexte de la fonction d’onde cosmologique, aux factorisations possibles en sous-problèmes (un parallèle direct avec les associaèdres pour les amplitudes).\n",
    "À chaque coupure ou partition, on associe des variables α,β,…\\alpha, \\beta,\\dotsα,β,… (analogues à des Mandelstam variables ou à des invariants kinematiques).\n",
    "Le cosmohedron en tant que polytope est l’intersection d’un certain nombre d’inégalités linéaires (et éventuellement quadratiques, selon les modèles) provenant de ces variables : { x∈RN:Mi(x)≥0 ∀i∈I}, \\big\\{\\, x\\in \\mathbb{R}^N : M_i(x)\\ge 0 \\ \\forall i \\in I\\big\\},{x∈RN:Mi​(x)≥0 ∀i∈I}, où chaque MiM_iMi​ capture une condition « physique » ou « combinatoire » de consistance.\n",
    "Pour exhiber la structure fractale, on définit une famille {Cn}\\{C_n\\}{Cn​} (analogues aux cosmohedra de plus en plus « raffinés ») via un processus itératif :\n",
    "Initialisation : C1C_1C1​ est un polytope de dimension ddd (par exemple, un associaèdre standard ou un polygone en 2D).\n",
    "Itération : Pour passer de CnC_nCn​ à Cn+1C_{n+1}Cn+1​, on effectue :\n",
    "L’introduction de nouvelles variables cinématiques (exemple : scission supplémentaire de l’énergie dans un canal de Feynman),\n",
    "L’ajout de nouvelles inégalités linéaires (ou combinatoires) qui forcent la convexité dans un espace plus grand,\n",
    "Le tout aboutit à un polytope Cn+1⊂RNn+1C_{n+1}\\subset \\mathbb{R}^{N_{n+1}}Cn+1​⊂RNn+1​.\n",
    "De cette manière, dim⁡(Cn)\\dim(C_n)dim(Cn​) augmente (ou du moins, l’espace ambiant RNn\\mathbb{R}^{N_n}RNn​ grandit), tandis que la projection de Cn+1C_{n+1}Cn+1​ sur certains sous-espaces ressemble de plus en plus à plusieurs copies (déformées) du polytope CnC_nCn​. C’est cette “auto-similarité” (même si souvent approchée et non exacte) qui peut nous donner la clé d’une structure fractale.\n",
    "\n",
    "1.2. Hypothèse d’auto-similarité asymptotique\n",
    "On formalise l’idée que « chaque nouveau polytope Cn+1C_{n+1}Cn+1​ contient plusieurs copies réduites de CnC_nCn​ ». Par exemple, on peut dire qu’il existe un nombre k≥2k\\ge 2k≥2 et un facteur d’échelle ρ∈(0,1)\\rho\\in (0,1)ρ∈(0,1) tels que, pour un grand nnn,\n",
    "Cn+1≈⋃i=1k(Φi(Cn)), C_{n+1} \\approx \\bigcup_{i=1}^k \\big( \\Phi_i(C_n)\\big),Cn+1​≈i=1⋃k​(Φi​(Cn​)),\n",
    "où Φi\\Phi_iΦi​ sont des transformations affines contractantes (i.e. ∥Φi(x)−Φi(y)∥≤ρ∥x−y∥\\|\\Phi_i(x) - \\Phi_i(y)\\|\\le \\rho\\|x-y\\|∥Φi​(x)−Φi​(y)∥≤ρ∥x−y∥).\n",
    "Dans la littérature fractale, quand on a une famille d’applications contractantes Φ1,…,Φk\\Phi_1,\\dots,\\Phi_kΦ1​,…,Φk​, il existe un ensemble (dit attracteur fractal) F⊂RmF\\subset \\mathbb{R}^mF⊂Rm tel que\n",
    "F=⋃i=1kΦi(F). F = \\bigcup_{i=1}^k \\Phi_i(F).F=i=1⋃k​Φi​(F).\n",
    "Si l’on parvient à montrer que {Cn}\\{C_n\\}{Cn​} converge (dans une topologie appropriée) vers un tel ensemble FFF, et que FFF n’est ni purement de dimension topologique dim⁡top∈N\\dim_{\\text{top}}\\in \\mathbb{N}dimtop​∈N ni trop mince (comme un ensemble de mesure zéro trop trivial), alors on peut conclure que FFF est fractal. On se servirait, par exemple, des résultats classiques de théorie des IFS (Iterated Function Systems, Barnsley et Hutchinson, 1981-1982).\n",
    "\n",
    "2. Critères de fractalité et preuve formelle\n",
    "Pour qu’un sous-ensemble F⊂RmF \\subset \\mathbb{R}^mF⊂Rm soit considéré comme « fractal », une définition classique (à la Falconer, ou à la Mandelbrot) repose sur :\n",
    "Dimension de Hausdorff dim⁡H(F)\\dim_{\\mathcal{H}}(F)dimH​(F) non entière ou strictement plus grande que sa dimension topologique.\n",
    "Un certain degré de self-similarité (exacte ou statistique).\n",
    "La dimension de Hausdorff peut être calculée ou estimée via la méthode de Hutchinson :\n",
    "Si FFF est l’attracteur d’un système d’applications contractantes {Φi}i=1k\\{\\Phi_i\\}_{i=1}^k{Φi​}i=1k​ avec un facteur d’échelle ρ<1\\rho < 1ρ<1 identique (ou ρi\\rho_iρi​ variables mais bornées) et certaines conditions de non-recouvrement trop fort (condition OSC — Open Set Condition), alors la dimension de Hausdorff dim⁡H(F)\\dim_{\\mathcal{H}}(F)dimH​(F) est la solution unique de :\n",
    "∑i=1kρis  =  1, \\sum_{i=1}^k \\rho_i^s \\;=\\; 1,i=1∑k​ρis​=1,\n",
    "où ρi\\rho_iρi​ est le plus grand facteur de contraction de Φi\\Phi_iΦi​. Généralement, la solution sss n’est pas un entier, d’où le caractère fractal.\n",
    "\n",
    "2.1. Argument de la preuve : suite de polytopes CnC_nCn​ convergente\n",
    "Énoncé : Supposons que la suite (Cn)(C_n)(Cn​) de polytopes (chacun potentiellement en dimension différente, ou projetée dans une dimension ≤m\\le m≤m) soit telle que, pour des constantes ρ<1\\rho<1ρ<1 et un entier k≥2k\\ge2k≥2, on ait :\n",
    "Cn+1⊂⋃i=1kΦn,i(Cn), C_{n+1} \\subset \\bigcup_{i=1}^k \\Phi_{n,i}(C_n),Cn+1​⊂i=1⋃k​Φn,i​(Cn​),\n",
    "avec Φn,i\\Phi_{n,i}Φn,i​ une application (au moins) contractante, et que le chevauchement entre les Φn,i(Cn)\\Phi_{n,i}(C_n)Φn,i​(Cn​) reste contrôlé (afin de satisfaire une version “dynamique” de l’Open Set Condition).\n",
    "Extraction d’un système contractant :\n",
    "Si, pour chaque nnn, les Φn,i\\Phi_{n,i}Φn,i​ sont εn\\varepsilon_nεn​-proches d’applications Φi\\Phi_iΦi​ (indépendantes de nnn) et εn→0\\varepsilon_n \\to 0εn​→0, alors dans la limite n→∞n\\to\\inftyn→∞, on obtient un système d’applications {Φi}i=1k\\{\\Phi_i\\}_{i=1}^k{Φi​}i=1k​ fixes et contractantes.\n",
    "Soit FFF l’attracteur fractal de ce système (au sens usuel de la théorie IFS). La suite {Cn}\\{C_n\\}{Cn​} peut alors être montrée convergente (par exemple, pour la distance de Hausdorff sur les compacts) vers l’ensemble FFF.\n",
    "Résultat : dim⁡H(F)=s\\dim_{\\mathcal{H}}(F) = sdimH​(F)=s, où sss est la solution de l’équation de Hutchinson :\n",
    "∑i=1kρis=1, \\sum_{i=1}^k \\rho_i^s = 1,i=1∑k​ρis​=1,\n",
    "(supposé non entier). Alors FFF est fractal, et CnC_nCn​ “devient” fractal dans la limite.\n",
    "Conséquence : On a donc formellement exhibé un objet (la limite) qui n’a plus de dimension Euclidienne standard, mais une dimension de Hausdorff non entière, possédant un motif de répétition (self-similarité). C’est précisément ce que l’on entend par « fractal » dans un sens rigoureux.\n",
    "\n",
    "2.2. Hypothèses nécessaires\n",
    "(H1) Contractions : Les Φn,i\\Phi_{n,i}Φn,i​ doivent réellement contracter les distances (ex. affinité avec un facteur ρ<1\\rho<1ρ<1).\n",
    "(H2) Contrôle de recouvrement : Il ne doit pas y avoir un trop grand recouvrement ou une accumulation pathologique (sinon la dimension de Hausdorff peut diverger ou se réduire à un objet trop simple).\n",
    "(H3) Approximation stable : On suppose que la suite Φn,i\\Phi_{n,i}Φn,i​ converge (au moins localement) vers {Φi}i=1k\\{\\Phi_i\\}_{i=1}^k{Φi​}i=1k​, ce qui permet de “geler” la dynamique dans la limite.\n",
    "Ces hypothèses sont, dans la pratique, difficiles à vérifier précisément pour les véritables cosmohedra ; elles sont plus simples à démontrer pour un modèle qui capture les mêmes règles combinatoires et dont la géométrie (les inégalités) est choisie pour permettre ces propriétés.\n",
    "\n",
    "3. Application à un « modèle cosmohedron fractal »\n",
    "Pour aller du formalisme théorique ci-dessus à un exemple concret, on peut définir explicitement :\n",
    "Un ensemble de variables (t1,…,tn)(t_1, \\dots, t_n)(t1​,…,tn​) modélisant les différents canaux d’énergie/moment (analogie aux coupes Feynman).\n",
    "Un polytope Cn⊂RnC_n\\subset \\mathbb{R}^nCn​⊂Rn défini par des inégalités du type 0≤t1≤t2≤⋯≤tn≤10 \\le t_1 \\le t_2 \\le \\dots \\le t_n \\le 10≤t1​≤t2​≤⋯≤tn​≤1 et des contraintes supplémentaires (ti+ti+1≤α ti−1+β)(t_i + t_{i+1} \\le \\alpha\\,t_{i-1} + \\beta)(ti​+ti+1​≤αti−1​+β), etc.\n",
    "Règles de subdivision : pour construire Cn+1C_{n+1}Cn+1​ à partir de CnC_nCn​, on rajoute des variables tn+1,…,tn+kt_{n+1}, \\dots, t_{n+k}tn+1​,…,tn+k​ et des inégalités analogues, de sorte que la projection sur {t1,…,tn}\\{t_1,\\dots, t_n\\}{t1​,…,tn​} se décompose en “copies” échelonnées de CnC_nCn​.\n",
    "Exemple schématique :\n",
    "Cn+1  =  ⋂i=1n+1{(t1,…,tn+1):ti≥0,  ∑j=1n+1tj=1,  … }, C_{n+1} \\;=\\; \\bigcap_{i=1}^{n+1} \\bigl\\{ (t_1,\\dots,t_{n+1}) : t_{i} \\ge 0,\\; \\sum_{j=1}^{n+1} t_j = 1,\\; \\dots \\bigr\\},Cn+1​=i=1⋂n+1​{(t1​,…,tn+1​):ti​≥0,j=1∑n+1​tj​=1,…},\n",
    "avec certaines conditions linéaires (ou affines) introduisant une auto-similarité. On peut prouver que, si on choisit bien les coefficients, alors on obtient une suite {Cn}\\{C_n\\}{Cn​} satisfaisant les hypothèses (H1), (H2) et (H3).\n",
    "La preuve de fractalité (au sens Hausdorff) s’articule alors sur la démonstration que la projection (ou section) dans un sous-espace de dimension 2 (ou plus) admet un recouvrement par Φn,i(Cn)\\Phi_{n,i}(C_n)Φn,i​(Cn​) avec un rapport d’échelle ρ<1\\rho<1ρ<1. Dès lors, la même théorie IFS s’applique et conclut qu’on obtient un attracteur fractal dans la limite.\n",
    "\n",
    "4. Conclusion et perspectives\n",
    "Construction rigoureuse :\n",
    "On a donné le schéma d’une construction formelle (suivant la logique de la théorie IFS) permettant de définir une suite de polytopes s’apparentant à une “version fractale” de cosmohedra. Les conditions de contraction et de non-recouvrement permettent l’utilisation des théorèmes standards de la géométrie fractale (Barnsley, Falconer, Hutchinson).\n",
    "Preuve de la fractalité :\n",
    "La démonstration repose sur la convergence vers un attracteur fractal  F\\,FF et l’évaluation de la dimension de Hausdorff par la formule ∑i=1kρis=1\\sum_{i=1}^k \\rho_i^s = 1∑i=1k​ρis​=1. On obtient ainsi, en général, un exposant sss non entier, prouvant le caractère fractal.\n",
    "Lien avec la physique :\n",
    "D’un point de vue strictement mathématique, l’existence ou non d’une fractalité dans le vrai “espace de configurations” d’un cosmohedron cosmologique reste conjecturale. Il faudrait prouver qu’en dimension (potentiellement) très élevée et avec des contraintes physiques (pôles d’amplitudes, invariances conformes, etc.), la construction reproduit les conditions de l’IFS.\n",
    "Remarque finale :\n",
    "Bien que cette approche donne un cadre théorique pour exhiber un objet fractal (et prouver rigoureusement ses propriétés de fractalité), son application exacte aux cosmohedra décrits dans la littérature de la fonction d’onde cosmologique exigerait des travaux d’adaptation. Néanmoins, c’est ainsi que l’on procéderait pour avoir un argument formel :\n",
    "Montrer que la “croissance” des polytopes répond à un schéma de self-similarité (au moins asymptotique),\n",
    "Démontrer, via un théorème standard d’attracteur IFS, que la dimension du lieu-limite est non entière,\n",
    "Conclure que la structure est fractale.\n",
    "En résumé, cette construction est rigoureuse si l’on respecte les hypothèses de contraction, de non-recouvrement et de convergence vers des transformations Φi\\Phi_iΦi​ fixes. Elle aboutit à une preuve formelle (dans le sens de la théorie des IFS) que le limite de la suite de polytopes est un ensemble fractal, et donc qu’il existe une structure fractale sous-jacente dans ce modèle “cosmohedron-like” à la limite n→∞n \\to \\inftyn→∞.\n",
    "\n",
    "\"\"\"\n",
    "resultats_md = main(mon_texte_de_preuve)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "44349990-50c7-4fb7-a62c-532d829c2bdc",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
